Skip to content

S04-07 JS基础-Ajax

[TOC]

Ajax基础知识铺垫

前端相关的技术点:

  • html(html5) 主要用来实现页面的排版布局
  • css(css3) 主要用来实现页面的样式美化
  • JavaScript(jQuery) 主要用来实现前端功能特效

采用上面的这些技术开发的页面和前端特效脚本需要放到服务器才能够对外提供服务,才能够让互联网上的网友看到。

Ajax基础知识铺垫

  • 客户端与服务器(计算机概述)
  • 通信协议(http/ftp/smtp/pop3…)
  • 网络、IP地址、端口、域名…
  • 静态网站、动态网站
  • 动态网站技术php常用语法
  • 同步与异步
  • ajax实现异步请求效果

客户端与服务器

本质上都是计算机,只不过样子不同,配置不同,应用场景不同(安装的应用软件不同)

  • 客户端主要用于普通上网用户

  • 服务器主要给上网用户提供后台服务

URL地址

URL地址的概念

URL (全称是Uniform Resource Locator)中文叫统一资源定位符,用于标识互联网上每个资源的唯一存放位置。浏览器只有通过URL地址,才能正确定位资源的存放位置,从而成功访问到对应的资源。

URL地址的组成部分

URL地址一般由三部组成:

  • 客户端与服务器之间的通信协议
  • 存有该资源的服务器名称
  • 资源在服务器上具体的存放位置

客户端和服务器的通信过程

图解通信过程

基于浏览器的开发者工具分析通信过程

服务器资源

浏览器如何请求数据

数据,也是服务器对外提供的一种资源。只要是资源,必然要通过请求-处理–响应的方式进行获取。

如果要在网页中请求服务器上的数据资源,则需要用到XMLHttpRequest对象。

XMLHttpRequest(简称xhr)是浏览器提供的js成员,通过它,可以请求服务器上的数据资源。

最简单的用法var xhrObj = new XMLHttpRequest()

资源的请求方式

客户端请求服务器时,请求的方式有很多种,最常见的两种请求方式分别为getpost请求。

  • get请求通常用于获取服务端资源(向服务器要资源)

    例如:根据URL地址,从服务器获取HTML文件、css文件、js文件、图片文件、数据资源等

  • post请求通常用于向服务器提交数据(往服务器发送资源)

    例如:登录时向服务器提交的登录信息、注册时向服务器提交的注册信息、添加用户时向服务器提交的用户信息等各种数据提交操作

网络相关概念

  • IP地址 (唯一的确定互联网上的一台计算机)
  • 域名 IP地址的别名,方便记忆
  • DNS 用于维护IP地址与域名的关系
  • 端口 用来确定计算机上的网络应用程序

通信协议理解

通信双方约定的规则

  • http/https 超为本传输协议
  • ftp 文件传输协议
  • smpt/pop3 邮件收发协议
  • ......

搭建服务器环境

wamp集成环境介绍

  • windows 操作系统
  • Apache 提供静态资源服务(html页面、js文件、css文件、图片。。。)
  • MySQL 数据库
  • php 编程语言,可以用来开发网站

wamp的安装配置

  • 参见详细文档

网站

网站由一系列页面组成(页面由js、css、图片、html标签。。。所有的这些文件都被称为资源)

静态网站

就是提前写好的html页面(包括图片、媒体文件。。。静态资源文件),并且部署到服务器上
静态网站主要存在的问题:

  • 随着网站规模的增大可维护性逐渐降低
  • 没有交互性

动态网站

动态指的是html页面是动态生成的,这里动态生成的不一定是一个完整的页面,有可能仅仅是页面的一部分,或者仅仅是数据(普通字符串、json、xml) 实现动态网站的技术:

  • php
  • java(jsp)
  • .net
  • Node.js
  • python
  • ......

Ajax基础

什么是Ajax

Ajax的全称是Asynchronous Javascript And XML (异步JavaScript和XML)。

通俗理解:在网页中利用XMLHttpRequest对象和服务器进行数据交互的方式,就是Ajax。

Ajax能让我们轻松实现网页服务器之间的数据交互

Web 程序最初的目的就是将信息(数据)放到公共的服务器,让所有网络用户都可以通过浏览器访问。

在此之前,我们可以通过以下几种方式让浏览器发出对服务端的请求,获得服务端的数据:

  • 地址栏输入地址,回车,刷新
  • 特定元素的 href 或 src 属性
  • 表单提交

这些方案都是我们无法通过或者很难通过代码的方式进行编程(对服务端发出请求并且接受服务端返回的响应),如果我们可以通过 JavaScript 直接发送网络请求,那么 Web 的可能就会更多,随之能够实现的功能也会更多,至少不再是“单机游戏”。 AJAX(Asynchronous JavaScript and XML),最早出现在 2005 年的 Google Suggest,是在浏览器端进行网络编程(发送请求、接收响应)的技术方案,它使我们可以通过javaScript 直接获取服务端最新的内容而不必重新加载页面。让 Web 更能接近桌面应用的用户体验。说白了,AJAX 就是浏览器提供的一套 API,可以通过 JavaScript 调用,从而实现通过代码控制请求与响应。实现网络编程

能力不够 API 凑。

Ajax典型应用场景

  • 用户名检测 : 注册用户时,通过ajax的形式,动态检测用户名是否被占用
  • 搜索提示 : 当输入搜索关键字时,通过ajax的形式,动态加载搜索提示列表
  • *数据分页显示 *: 当点击页码值的时候,通过ajax的形式,根据页码值动态刷新表格的数据
  • 数据的增删改查 : 数据的添加、删除、修改、查询操作,都需要通过ajax的形式,来实现数据的交互

隐藏帧iframe模拟Ajax效果

html
<!-- 前端 --> 
<form action="index.php" method="post" target="getAjax">
   <h2>用户登录</h2>
   <ul>
         <li>
            <span>用户名:</span>
            <input type="text" value="" name="username" >
            <span class="info"></span>
         </li> 
         <li>
            <span>密 码:</span>
            <input type="password" value="" name="password">
            <span class="="info></span>
         </li>
         <li>
            <input type="submit" value="提交" id="sub">
         </li>
   </ul>
</form>

<iframe name="getAjax" width="100" height="50" ></iframe>
php
// 后端
$username = $_POST['username'];
$password = $_POST['password'];
if( $username == 'admin' && $password == '111' ){
   echo '登录成功';
}else {
   echo '登录失败';
}
php
   // 前端不变,后端这样写,可以在iframe以外的元素中接收到提示信息
    $username = $_POST['username'];
    $password = $_POST['password'];
    // 以下的写法可以
    if( $username == 'admin' && $password == '111' ){
        echo <<<EOF
<script type='text/javascript'>
    parent.document.getElementById('info').innerHTML = '登录成功';
</script>
EOF;
    }else {
        echo <<<EOF
<script type='text/javascript'>
    parent.document.getElementById('info').innerHTML = '登录失败';
</script>
EOF;
    }

快速上手

js
// 1. 创建一个 XMLHttpRequest 类型的对象 —— 相当于打开了一个浏览器
var xhr = new XMLHttpRequest(); // IE7开始支持
//var xhr = new ActiveXObject('Microsoft.XMLHTTP'); // IE6支持

// 2. 打开与一个网址之间的连接 —— 相当于在地址栏输入访问地址
xhr.open('GET', './time.php');

// 3. 通过连接发送一次请求 —— 相当于回车或者点击访问发送请求
xhr.send(null);

// 4. 指定 xhr 状态变化事件处理函数 —— 相当于处理网页呈现后的操作
xhr.onreadystatechange = function () {
   // 通过 xhr 的 readyState 判断此次请求的响应是否接收完成
   if (this.readyState === 4) {
      // 通过 xhr 的 responseText 获取到响应的响应体
     console.log(this);
     var data = this.responseText;
     console.log(data);
   }
}

readyState

由于 readystatechange 事件是在 xhr 对象状态变化时触发(不单是在得到响应时),也就意味着这个事件会被触发多次,所以我们有必要了解每一个状态值代表的含义:

readyState状态描述说明
0UNSENT代理(XHR)被创建,但尚未调用 open() 方法。
1OPENEDopen() 方法已经被调用,建立了连接。
2HEADERS_RECEIVEDsend() 方法已经被调用,并且已经可以获取状态行和响应头
3LOADING响应体下载中, responseText 属性可能已经包含部分数据。
4DONE响应体下载完成,可以直接使用 responseText 。

时间轴

js
var xhr = new XMLHttpRequest()
console.log(xhr.readyState)
// => 0
// 初始化 请求代理对象
xhr.open('GET', 'time.php')
console.log(xhr.readyState)
// => 1
// open 方法已经调用,建立一个与服务端特定端口的连接
xhr.send()
xhr.addEventListener('readystatechange', function () {
   switch (this.readyState) {
         case 2:
            // => 2
            // 已经接受到了响应报文的响应头
            // 可以拿到头
            // console.log(this.getAllResponseHeaders())
            console.log(this.getResponseHeader('server'))
            // 但是还没有拿到体
            console.log(this.responseText)
            break
         case 3:
            // => 3
            // 正在下载响应报文的响应体,有可能响应体为空,也有可能不完整
            // 在这里处理响应体不保险(不可靠)
            console.log(this.responseText)
            break
         case 4:
            // => 4
            // 一切 OK (整个响应报文已经完整下载下来了)
            // 这里处理响应体
            console.log(this.responseText)
            break
   }
})

通过理解每一个状态值的含义得出一个结论:一般我们都是在 readyState 值为 4 时,执行响应的后续逻辑。

js
xhr.onreadystatechange = function () {
   if (this.readyState === 4) {
      // 后续逻辑......
   }
}

遵循 HTTP

本质上 XMLHttpRequest 就是 JavaScript 在 Web 平台中发送 HTTP 请求的手段,所以我们发送出去的请求任然是HTTP 请求,同样符合 HTTP 约定的格式:

js
// 创建XMLHttpRequest对象
var xhr = new XMLHttpRequest();
// 设置请求报文的请求行
xhr.open('GET', './time.php')
// 设置请求头
xhr.setRequestHeader('Accept', 'text/plain')
// 设置请求体
xhr.send(null)
xhr.onreadystatechange = function () {
   if (this.readyState === 4) {
         // 获取响应状态码
         console.log(this.status)
         // 获取响应状态描述
         console.log(this.statusText)
         // 获取响应头信息
         console.log(this.getResponseHeader('Content‐Type')) // 指定响应头
         console.log(this.getAllResponseHeader()) // 全部响应头
         // 获取响应体
         console.log(this.responseText) // 文本形式
         console.log(this.responseXML) // XML 形式,了解即可不用了
   }
}

参考链接: https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequesthttps://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest

XMLHttpRequest的基本使用

XMLHttpRequest(简称xhr)是浏览器提供的Javascript对象,可以通过它请求服务器上的数据资源。之前所学的jQuery 中的 Ajax函数,就是基于xhr 对象封装出来的。

js
// xhr对象 console.log(xhr)后的结果
XMLHttpRequest

    onabort: null
    onerror: null
    onload: null
    onloadend: null
    onloadstart: null
    onprogress: null
+    onreadystatechange: ƒ ()
    ontimeout: null

+    readyState: 4
+    status: 200
    statusText: "OK"

    response: "Ajax Return"
+    responseText: "Ajax Return"
    responseType: ""
    responseURL: "http://www.web21.com/Ajax/d01_echo.php"
+    responseXML: null

    timeout: 0
    upload: XMLHttpRequestUpload {onloadstart: null, onprogress: null, onabort: null, onerror: null, onload: null, …}
    withCredentials: false

xhr对象创建和兼容处理

js
// 兼容写法一
var xhr = null;
if( window.XMLHttpRequest ){
   xhr = new XMLHttpRequest();   // IE7开始支持
} else {
   xhr = new ActiveXObject('Microsoft.XMLHTTP');  // IE6支持
}

// 兼容写法二
var xhr = null;
try{
   xhr = new XMLHttpRequest();
}catch(e){
   xhr = new ActiveXObject('Microsoft.XMLHTTP');
}

// 兼容写法三
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');

open准备发送

GET请求

通常在一次 GET 请求过程中,参数传递都是通过 URL 地址中的 ? 参数传递。 步骤:

  • 创建xhr对象
  • 调用xhr.open()函数
  • 调用xhr.send()函数
  • 监听xhr.onreadystatechange 事件
js
// 注意点
var url = encodeURI('./delete.php?id=1&name=张三');
xhr.open('GET', url)
xhr.send(null);
js
// 1、创建xhr对象
var xhr = new XMLHttpRequest()

// 2、调用xhr.open()函数
xhr.open('GET', './delete.php?id=1') // GET请求传递参数通常使用的是问号传参;这里可以在请求地址后面加上参数,从而传递数据到服务端

// 3、调用xhr.send()函数
xhr.send(null) // 一般在 GET 请求时无需设置响应体,可以传 null 或者干脆不传

// 4、监听xhr.onreadystatechange 事件
xhr.onreadystatechange = function () {
   if (xhr.readyState === 4 && xhr.status === 200) { // xhr的请求状态readyState、服务器的响应状态status
      console.log(this.responseText)
   }
}
// 一般情况下 URL 传递的都是参数性质的数据,而 POST 一般都是业务数据

注意:在使用GET方式传递参数的时候,如果参数是中文的话,那么在IE浏览器中会返回一段乱码,会出错

js
// 解决方法:
// encodeURI(param) // 对中文param使用encodeURI方法进行编码

POST 请求

POST 请求过程中,都是采用请求体承载需要提交的数据。

步骤:

  • 创建xhr 对象
  • 调用xhr.open()函数
  • 设置Content-Type属性(固定写法)
  • 调用xhr.send()函数,同时指定要发送的数据
  • 监听xhr.onreadystatechange事件
js
// 注意点
xhr.open('POST', './add.php');
xhr.setRequestHeader('Content‐Type', 'application/x‐www‐form‐urlencoded');
xhr.send('key1=value1&key2=value2');
js
  var xhr = new XMLHttpRequest()
  // open 方法的第一个参数的作用就是设置请求的 method
  xhr.open('POST', './add.php')
  // 设置请求头中的 Content‐Type 为 application/x‐www‐form‐urlencoded
  // 标识此次请求的请求体格式为 urlencoded 以便于服务端接收数据
+    xhr.setRequestHeader('Content‐Type', 'application/x‐www‐form‐urlencoded')
  // 需要提交到服务端的数据可以通过 send 方法的参数传递
  // 格式:key1=value1&key2=value2
+ xhr.send('key1=value1&key2=value2')
  xhr.onreadystatechange = function () {
      if (xhr.readyState === 4 && xhr.status === 200) {
          console.log(this.responseText)
      }
  }

Content-Type常见类型

Content-Type(内容类型),一般是指网页中存在的 Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件,这就是经常看到一些 PHP 网页点击的结果却是下载一个文件或一张图片的原因。

Content-Type 标头告诉客户端实际返回的内容的内容类型。

  • 语法:

    js
    Content-Type: text/html; charset=utf-8
    Content-Type: multipart/form-data; boundary=something
  • 常见的媒体格式类型:

    • text/html : HTML格式
    • text/plain :纯文本格式
    • text/xml : XML格式
    • image/gif :gif图片格式
    • image/jpeg :jpg图片格式
    • image/png:png图片格式
  • 以application开头的媒体格式类型:

    • application/xhtml+xml :XHTML格式
    • application/xml: XML数据格式
    • application/atom+xml :Atom XML聚合格式
    • application/json: JSON数据格式
    • application/pdf:pdf格式
    • application/msword : Word文档格式
    • application/octet-stream : 二进制流数据(如常见的文件下载)
    • application/x-www-form-urlencoded<form encType=””>中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
  • 上传文件时使用的媒体格式类型:

    • multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式

同步与异步

关于同步与异步的概念在生活中有很多常见的场景,举例说明。

同步:一个人在同一个时刻只能做一件事情,在执行一些耗时的操作(不需要看管)不去做别的事,只是等待 异步:在执行一些耗时的操作(不需要看管)去做别的事,而不是等待

xhr.open() 方法第三个参数要求传入的是一个 bool 值,其作用就是设置此次请求是否采用异步方式执行,默认为 true ,如果需要同步执行可以通过传递 false 实现:

js
console.log('before ajax')
var xhr = new XMLHttpRequest()
// 默认第三个参数为 true 意味着采用异步方式执行
+ xhr.open('GET', './time.php', true)
xhr.send(null)
xhr.onreadystatechange = function () {
   if (this.readyState === 4) {
      // 这里的代码最后执行
      console.log('request done')
   }
}
console.log('after ajax')

如果采用同步方式执行,false,则代码会卡死在 xhr.send() 这一步:

js
console.log('before ajax')
var xhr = new XMLHttpRequest()
// 同步方式
xhr.open('GET', './time.php', false)
// 同步方式 执行需要 先注册事件再调用 send,否则 readystatechange 无法触发
xhr.onreadystatechange = function () {
   if (this.readyState === 4) {
      // 这里的代码最后执行
      console.log('request done')
   }
}
xhr.send(null)
console.log('after ajax')

演示同步异步差异。 一定在发送请求 send() 之前注册 readystatechange (不管同步或者异步)

  • 为了让这个事件可以更加可靠(一定触发),一定是先注册

了解同步模式即可,切记不要使用同步模式。 至此,我们已经大致了解了 A JAX 的基本 API 。

URL编码与解码

URL地址中,只允许出现英文相关的字母、标点符号、数字,因此,在URL地址中不允许出现中文字符。

如果URL中需要包含中文这样的字符,则必须对中文字符进行编码(转义)。

URL编码的原则:使用安全的字符(没有特殊用途或者特殊意义的可打印字符)去表示那些不安全的字符。

URL编码原则的通俗理解:使用英文字符去表示非英文字符

编码、解码API:

  • encodeURI() - 编码的函数

  • decodeURI() - 解码的函数

注意:

由于浏览器会自动对URL地址进行编码操作,因此,大多数情况下,程序员不需要关心URL地址的编码与解码操作

响应数据格式

提问:如果希望服务端返回一个复杂数据,该如何处理? 关心的问题就是服务端发出何种格式的数据,这种格式如何在客户端用 JavaScript 解析。

数据交换格式,就是服务器端客户端之间进行数据传输与交换的格式。 前端领域,经常提及的两种数据交换格式分别是XMLJSON。其中XML用的非常少,所以,我们重点要学习的数据交换格式就是JSON。

XML

一种数据描述手段 老掉牙的东西,简单演示一下,不在这里浪费时间,基本现在的项目不用了。 淘汰的原因:

  1. 数据冗余太多,不利于大量数据的网络传输
  2. 解析不太方便
js
window.onload = function(){
   // ajax
   var sub = document.getElementById('sub');
   var oUser = document.getElementById('username');
   var oPass = document.getElementById('password');
   var oInfo = document.getElementById('info');

   sub.onclick = function(){
         var uname = oUser.value;
         var pword = oPass.value;
         var xhr = null;
         try{
            xhr = new XMLHttpRequest();
         }catch(e){
            xhr = new ActiveXObject('Microsoft.XMLHTTP');
         }

         xhr.open('post','index.php');
         xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');

         xhr.send('username='+uname+'&password='+pword);
         
         xhr.onreadystatechange = function(){
            if( this.readyState === 4 && this.status === 200 ){
               var data = this.responseXML;
               // 对返回的数据进行处理
               var oList = data.getElementsByTagName('booklist')[0];
               var aBook = oList.getElementsByTagName('book');
               var aInfo = [];

               for( var i=0;i<aBook.length;i++ ){
                     var tmp = [];
                     tmp.push(aBook[i].getElementsByTagName('name')[0].innerHTML);
                     tmp.push(aBook[i].getElementsByTagName('author')[0].innerHTML);
                     tmp.push(aBook[i].getElementsByTagName('desc')[0].innerHTML);
                     aInfo.push(tmp);    // 将一个一维数组push到另一个一维数组中去就得到一个二维数组
               }
               console.log(aInfo);
            }
         };
   };
};
php
<?php
    header('Content-Type:text/xml;');
?>
<?xml version='1.0' encoding='utf-8'  ?>
<booklist>
    <book>
        <name>皇帝内经</name>
        <author>西汉某人</author>
        <desc>是中国影响极大的一部医学著作,被称为医之始祖</desc>
    </book>
    <book>
        <name>伤寒杂病论</name>
        <author>张仲景</author>
        <desc>奠定了理、法、方、药的理论基础</desc>
    </book>
</booklist>

JSON

概念:

JSON的英文全称是JavaScript Object Notation,即“JavaScript对象表示法”。简单来讲,JSON就是Javascript 对象和数组的字符串表示法,它使用文本表示一个JS对象或数组的信息,因此,JSON的本质是字符串

作用:

JSON是一种轻量级的文本数据交换格式,在作用上类似于XML,专门用于存储和传输数据,但是JSON比XML更小、更快、更易解析

现状:

JSON是在2001年开始被推广和使用的数据格式,到现今为止,JSON已经成为了主流的数据交换格式

JSON的两种结构:

  • 对象结构

    对象结构在JSON中表示为*{}括起来的内容*。数据结构为{ key: value, key: value,...}的键值对结构。其中,key必须是使用英文的双引号包裹的字符串,value

    的数据类型可以是数字字符串布尔值null数组对象6种类型(函数、undefined不行)。

  • 数组结构

    数组结构在JSON中表示为*[]括起来的内容*。数据结构为[ "java" , "javascript",30, true ...] .数组中数据的类型可以是数字字符串布尔值null数组

    象*6种类型。

js
// 语法

// 数组
var arr = ['张三','31','男']; 
// 对象
var obj = {'name':'张三','age': '31','sex': '男','hobby': ['篮球','排球'],'girlfriend': {'name': '李四','age':30}};
var obj = {
   name:'张三',
   age: 31,
   sex: '男',
   hobby: ['篮球','排球'],
   girlfriend: {
      name: '李四',
      age:30
   }
};
// json
{
   "name":"张三",
   "age":31,
   "lover":["篮球","排球"],
   "friend":{
      "high": "180cm",
      "weight": "80kg"
   }
}

JSON语法注意事项:

  • 属性名必须使用双引号包裹
  • 字符串类型的值必须使用双引号包裹
  • JSON中不允许使用单引号表示字符串
  • JSON中不能写注释
  • JSON的最外层必须是对象或数组格式
  • 不能使用undefined 或函数作为JSON的值

JSON的作用 :在计算机与网络之间存储和传输数据。

JSON 的本质 :用字符串来表示Javascript对象数据或数组数据

JSON和普通的js对象的区别:

  • JSON数据没有变量
  • JSON形式的数据结尾没有分号
  • JSON数据中的键必须用双引号包裹,单引号都不行

JSON和JS对象的互转

  • JSON.parse(string) - 把JSON转化为对象
  • JSON.stringify(obj) - 把对象转化为JSON
js
  var str = '{"name":"张三","age":31}';

+ var obj = JSON.parse(str)   // 把json形式的字符串转成对象

+ var str1 = JSON.stringify(obj);   // 把对象转换成字符串

+ var d = eval("("+str+")");  // eval的作用是将字符串解析成js代码并执行,但是有安全隐患(不推荐使用)

  // 访问
  console.log(d.name);
  console.log(d.age);

也是一种数据描述手段,类似于 JavaScript 字面量方式 服务端采用 JSON 格式返回数据,客户端按照 JSON 格式解析数据。

不管是 JSON 也好,还是 XML,只是在 A JAX 请求过程中用到,并不代表它们之间有必然的联系,它们只是数据协议罢了

序列化和反序列化

数据对象转换为字符串的过程,叫做序列化,例如:调用JSON.stringify()函数的操作,叫做JSON序列化。

字符串转换为数据对象的过程,叫做反序列化,例如:调用JSON.parse()函数的操作,叫做JSON反序列化。

PHP开发json

  • PHP生成json数据
php
// $arr 所有非资源类型的数据
json_encode($arr);    // 把数组转换成json形式的字符串
php
$arr = array(1,2,3);
echo json_encode($arr);   // [1,2,3] 这是一个字符串,不是数组,需要通过JSON.parse(data);解析成数组

处理响应数据渲染

模板引擎: artTemplate:https://aui.github.io/art-template/

模板引擎实际上就是一个 API,模板引擎有很多种,使用方式大同小异,目的为了可以更容易的将数据渲染到HTML中

AJAX 请求封装

函数就可以理解为一个想要做的事情,函数体中约定了这件事情做的过程,直到调用时才开始工作。 将函数作为参数传递就像是将一个事情交给别人,这就是委托的概念

js
/**
* 发送一个 AJAX 请求
* @param {String} method 请求方法
* @param {String} url 请求地址
* @param {Object} params 请求参数
* @param {Function} done 请求完成过后需要做的事情(委托/回调)
*/
function ajax(method, url, params, done) {
   // 统一转换为大写便于后续判断
   method = method.toUpperCase()
   // 对象形式的参数转换为 urlencoded 格式
   var pairs = []
   for (var key in params) {
         pairs.push(key + '=' + params[key])
   }
   var querystring = pairs.join('&')
   var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
   xhr.addEventListener('readystatechange', function () {
         if (this.readyState !== 4) return
         // 尝试通过 JSON 格式解析响应体
         try {
            done(JSON.parse(this.responseText))
         } catch (e) {
            done(this.responseText)
         }
   })
   // 如果是 GET 请求就设置 URL 地址 问号参数
   if (method === 'GET') {
         url += '?' + querystring
   }
   xhr.open(method, url)
   // 如果是 POST 请求就设置请求体
   var data = null
   if (method === 'POST') {
         xhr.setRequestHeader('Content‐Type', 'application/x‐www‐form‐urlencoded')
         data = querystring
   }
   xhr.send(data)
}
ajax('get', './get.php', { id: 123 }, function (data) {
   console.log(data)
})
ajax('post', './post.php', { foo: 'posted data' }, function (data) {
   console.log(data)
})

jQuery 中的 AJAX

浏览器中提供的XMLHttpRequest用法比较复杂,所以jQuery对 XMLHttpRequest进行了封装,提供了一系列 Ajax相关的函数,极大地降低了Ajax的使用难度

jQuery中发起 Ajax请求最常用的三个方法如下

  • $.get()
  • $.post()
  • $.ajax()

参考: http://www.jquery123.com/category/ajax/http://www.w3school.com.cn/jquery/jquery_ref_ajax.asp

$.ajax

相比于$.get()$.post()函数,jQuery 中提供的$.ajax()函数,是一个功能比较综合的函数,它允许我们对Ajax请求进行更详细的配置

语法:

js
$.ajax({
    type: '', // 请求的方式,例如GET或POST
    url: '',  // 请求的URL地址
    data: {}, // 这次请求要携带的数据
    success: function(res){} // 请求成功之后的回调函数
});

示例:

html
<button id="btnAjaxGet">Ajax请求-GET-获取图书</button>
<button id="btnAjaxPost">Ajax请求-POST-添加图书</button>

<script src="lib/jquery/jquery.js"></script>
<script>
    $(function(){
        // Ajax请求-GET-获取图书
        $('#btnAjaxGet').on('click', function(){
            $.ajax({
+                type: 'GET',
                url: 'http://www.liulongbin.top:3006/api/getbooks',
                // data: {id: 1},
                success: function(res){
                    console.log(res);
                }
            });
        });

        // Ajax请求-POST-添加图书
        $('#btnAjaxPost').on('click', function(){
            $.ajax({ 
+                type: 'POST',
                url: 'http://www.liulongbin.top:3006/api/addbook',
                data: {bookname: '禁区之狐', author: '林海听涛', publisher: '起点'},
                success: function(res){
                    console.log(res);
                }
            });
        });    
    });
</script>

$.ajax` 中不同的回调函数

js
$.ajax({
    url: './get.php',
    type: 'get',
    dataType: 'json',
    data: { id: 1 },
    // 请求发起之前触发
+    beforeSend: function (xhr) {
        console.log('before send')
    },
    // 请求成功之后触发(响应状态码 200)
+    success: function (data) {
        console.log(data)
    },
    // 请求失败触发
+    error: function (err) {
        console.log(err)
    },
    // 请求完成触发(不管成功与否)
+    complete: function () {
        console.log('request completed')
    }
})

常用选项参数介绍:

  • url:请求地址
  • type:请求方法,默认为 get
  • dataType:服务端响应数据类型
  • contentType:请求体内容类型,默认 application/x-www-form-urlencoded
  • data:需要传递到服务端的数据,如果 GET 则通过 URL 传递,如果 POST 则通过请求体传递
  • timeout:请求超时时间
  • beforeSend:请求发起之前触发
  • success:请求成功之后触发(响应状态码 200)
  • error:请求失败触发
  • complete:请求完成触发(不管成功与否)

$.get

GET 请求快捷方法

jQuery 中 $.get() 函数的功能单一,专门用来发起get请求,从而将服务器上的资源请求到客户端来进行使用。

语法:

js
$.get(url, [data], [callback])
  • url:要请求的资源地址
  • data:请求资源期间要携带的参数
  • callback:请求成功时的回调函数

示例:

html
    <button id="btnGet1">GET请求-不带参数</button>
    <button id="btnGet2">GET请求-带参数</button>
    
+ <script src="lib/jquery/jquery.js"></script>
    <script>
        $(function(){
            // GET请求-不带参数
            $('#btnGet1').on('click', function(){
+                $.get('http://www.liulongbin.top:3006/api/getbooks', function(res){
                    console.log(res);
                });
            });

            // GET请求-带参数
            $('#btnGet2').on('click', function(){
+                $.get('http://www.liulongbin.top:3006/api/getbooks', {id: 1}, function(res){
                    console.log(res);
                });
            });

        });
    </script>

$.post

POST 请求快捷方法

jQuery中 $.post(函数的功能单一,专门用来发起post请求,从而向服务器提交数据

语法:

js
$.post(url, [data], [callback])
  • url:要请求的资源地址
  • data:要提交的数据
  • callback:请求成功时的回调函数

示例:

html
    <button id="btnPost">POST请求-添加图书</button>

    <script src="lib/jquery/jquery.js"></script>
    <script>
        $(function(){
            // POST请求-添加图书
            $('#btnPost').on('click', function(){
+                $.post(
+                    'http://www.liulongbin.top:3006/api/addbook',
+                    {bookname: "长夜余火", author: "爱潜水的乌贼", publisher: "起点出版社"},
                    function(res){
                        console.log(res);
                    }
                );
            });
        });
    </script>

接口

接口的概念

使用Ajax请求数据时,被请求的URL地址,就叫做数据接口(简称接口)。同时,每个接口必须有请求方式

例如:

接口测试工具

工具:PostMan

为了验证接口能否被正常被访问,我们常常需要使用接口测试工具,来对数据接口进行检测。

好处:接口测试工具能让我们在不写任何代码的情况下,对接口进行调用测试

接口文档

接口文档,顾名思义就是接口的说明文档,它是我们调用接口的依据。好的接口文档包含了对接口URL参数以及输出内容的说明,我们参照接口文档就能方便的知道接口的作用,以及接口如何进行调用。

接口文档的组成部分

  • 接口名称:用来标识各个接口的简单说明,如登录接口获取图书列表接口
  • 接口URL:接口的调用地址
  • 调用方式:接口的调用方式,如GETPOST
  • 参数格式:接口需要传递的参数,每个参数必须包含参数名称参数类型是否必选参数说明这4项内容
  • 响应格式:接口的返回值的详细描述,一般包含数据名称数据类型说明3项内容
  • 返回示例(可选):通过对象的形式,例举服务器返回数据的结构

案例:图书管理

  • UI界面

  • 案例用到的库和插件

    用到的css库:bootstrap.css

    用到的js库:jquery.js

    用到的VSCode插件:Bootstrap 3 Snippets

案例:聊天机器人

  • UI界面

  • 用到的插件、技术

    jquery.min.js

    jquery-ui.min.js

    jquery.mousewheel.js

    scroll.js

    接口

    新接口1:http://www.liulongbin.top:3006/api/robot

    新接口2:http://www.liulongbin.top:3006/api/synthesize

  • 实现步骤

    1、梳理案例的代码结构

    1)梳理页面的U布局

    2)将业务代码抽离到chat.js 中

    3)了解resetui()函数的作用

    2、将用户输入的内容渲染到聊天窗口

    3、发起请求获取聊天消息

    4、将机器人的聊天内容转为语音

    5、通过 <audio> 播放语音

    6、使用回车键发送消息

form表单中的Ajax

form表单的基本使用

表单在网页中主要负责数据采集功能。HTML中的<form>标签,就是用于采集用户输入的信息,并通过<form>标签的提交操作,把采集到的信息提交到服务器端进行处理。

表单由三个基本部分组成

1、表单标签:form

2、表单域:文本框、密码框、隐藏域、多行文本框、复选框、单选框、下拉选择框、文件上传框等

3、表单按钮:提交按钮、清空按钮

form标签的属性

<form>标签的属性则是用来规定如何把采集到的数据发送到服务器。

属性描述
actionURL规定当提交表单时向何处发送表单数据。
autocompleteon | off规定是否启用表单的自动完成功能。
enctypeapplication/x-www-form-urlencoded | multipart/form-data | text/plain规定在发送表单数据之前如何对其进行编码。
methodget | post规定用于发送 form-data 的 HTTP 方法。
nameform_name规定表单的名称。
novalidatenovalidate如果使用该属性,则提交表单时不进行验证。
target_blank | _self | _parent | _top | framename规定在何处打开 action URL。

注意 : 在涉及到文件上传的操作时,必须将enctype的值设置为multipart/form-data 如果表单的提交不涉及到文件上传操作,则直接将enctype的值设置为 application/x-www-form-urlencoded 即可!

表单的同步提交

通过点击submit按钮,触发表单提交的操作,从而使页面跳转到action URL的行为,叫做表单的同步提交。

表单的同步提交的缺点

1、form表单同步提交后,整个页面会发生跳转,跳转到action URL所指向的地址,用户体验很差

2、form表单同步提交后,页面之前的状态和数据会丢失

解决方案

表单只负责采集数据,Ajax负责将数据提交到服务器

通过Ajax提交表单数据

监听表单提交事件

在jQuery中,可以使用如下两种方式,监听到表单的提交事件

js
// 监听表单提交数据的两种方法

+ $('#frm').submit(function(e){
    alert('监听表单提交数据 - submit');
  
    // 阻止表单的默认提交行为
+   e.preventDefault();
});

+ $('#frm').on('submit', function(e){
    alert('监听表单提交数据 - on - submit');
  
    // 阻止表单的默认提交行为
+   e.preventDefault();
});

阻止表单的默认提交行为

当监听到表单的提交事件以后,可以调用事件对象的 event.preventDefault() 函数,来阻止表单的提交和页面的跳转,如上例。

快速获取表单中的数据

为了简化表单中数据的获取操作,jQuery提供了 serialize() 函数,其语法格式如下:

js
$(selector).serialize ()

serialize() 函数的好处:可以一次性获取到表单中的所有的数据

注意 :在使用serialize() 函数快速获取表单数据时,必须为每个表单元素添加name属性!

案例:评论列表

UI界面

接口

  • 请求根路径

http://www.liulongbin.top:3006

  • 评论列表
    • url: /api/cmtlist
    • type: get
    • 参数:无
  • 发表评论
    • url: /api/addcmt
    • type: post
    • 参数:username, content

模板引擎

模板引擎的基本概念

渲染UI结构时遇到的问题

代码是通过字符串拼接的形式,来渲染Ul结构。

如果UI结构比较复杂,则拼接字符串的时候需要格外注意引号之前的嵌套。且一旦需求发生变化,修改起来也非常麻烦

什么是模板引擎

模板引擎,顾名思义,它可以根据程序员指定的模板结构数据,自动生成一个完整的HTML页面。

模板引擎的好处

1、减少了字符串的拼接操作

2、使代码结构更清晰

3、使代码更易于阅读与维护

art-template模板引擎

art-template是一个简约、超快的模板引擎。中文官网首页为http://aui.github.io/art-template/zh-cn/index.html

安装

在浏览器中访问http://aui.github.io/art-template/zh-cn/docs/installation.html页面,将art-template下载到本地,然后通过script标签加载到网页上进行使用。

art-template使用步骤

1、导入art-template

2、定义数据

3、定义模板

4、调用template函数

5、渲染HTML结构

art-template标准语法

art-template 提供了 这种语法格式,在 内可以进行变量输出,或循环数组等操作,这种 语法在art-template中被称为标准语法

标准语法 - 变量
html
{{set temp = xxx}}
标准语法 - 输出
js
{{ value }}
{{ obj.key }}
{{ obj['key'] }}
{{ a ? b : c }}
{{ a || b }}
{{ a + b }}

在语法中,可以进行变量的输出、对象属性的输出、三元表达式输出、逻辑或输出、加减乘除等表达式输出。

标准语法 - 原文输出
js
{{ @ value }}

如果要输出的value值中,包含了HTML标签结构,则需要使用原文输出语法,才能保证HTML标签被正常渲染。

html
标准语法 - 条件输出

如果要实现条件输出,则可以在中使用if ... else if .../if 的方式,进行按需输出。

html
{{if value}}按需输出的内容{{/if}}
{{if v1}}按需输出的内容{{else if v2}}按需输出的内容{{/if}}
标准语法 - 循环输出

如果要实现循环输出,则可以在内,通过each语法循环数组,当前循环的索引(从0开始)使用$index 进行访问,当前的循环项使用$value 进行访问。

html
{{each target}}
  {{$index}} {{$value}}
{{/each}}

注意

  1. target 支持 arrayobject 的迭代,其默认值为 $data
  2. $value$index 可以自定义:NaN
标准语法 - 模板继承
html
{{extend './layout.art'}}
{{block 'head'}} ... {{/block}}
标准语法 - 子模板
html
{{include './header.art'}}
{{include './header.art' data}}
标准语法 - 过滤器

过滤器的本质,就是一个function处理函数。

语法:

html
{{date | timestamp | dateFormat 'yyyy-MM-dd hh:mm:ss'}}
  • value:需要处理的参数
  • filterName:过滤器的处理函数

过滤器语法类似管道操作符,它的上一个输出作为下一个输入。

定义过滤器

语法:

js
template.defaults.imports.filterName = function (value) { /*return处理的结果*/}

示例:

html
<div>注册时间:{{regTime | dateFormat}}</div>

定义一个格式化时间的过滤器dateFormat 如下:

js

art-template的API

  • template(filename, data) - 基于模板名渲染模板

    参数

    • filename - 模板文件的路径地址(也可以是script标签中的id名)
    • data - 替换对象键值
  • template.compile(source, options) - 将模板源代码编译成函数

    参数

    • source - 模板字符串
    • options -
  • template.render(source, data, options) - 将模板源代码编译成函数并立刻执行

    参数

    • source - 模板字符串
    • data - 替换对象键值
    • options -

模板引擎的实现原理

  • 模板引擎的底层原理:字符串的替换
  • 在ECMAScript 6的 `` 字符串中,可以使用 ${变量名} 来引用变量
  • art-template 模板引擎,不仅可以在前端使用,也可以在node中使用
  • 模板引擎不关心字符串的内容,只关心它能认识的模板标记语法: / <%%>

实现简易的模板引擎

  • 实现步骤

    • 定义模板结构

      html
          <script type="text/html" id="tplUser">
              <div>姓名:{{name}}</div>
              <div>年龄:{{  age}}</div>
              <div>性别:{{ gender}}</div>
              <div>工资:{{  salary }}</div>
              <div>地址:{{city  }}</div>
          </script>
    • 预调用模板引擎

      js
          var data = {name: '胡八一', age: 35, gender: '男', salary: '20000', city: '北京'};
      
      +    var tplStr = template('tplUser', data);
      
          document.querySelector('#userBox').innerHTML = tplStr;
    • 封装template函数

      js
          function template(id, data){
              var tpl = document.getElementById(id).innerHTML;
      +        return tpl.replace(/{{\s*([a-zA-Z_0-9]+)\s*}}/g, function(res, subRes){
      +            return data[subRes];
              });
          }
    • 导入并使用自定义的模板引擎

案例:新闻列表

UI界面

接口

  • 请求根路径

http://www.liulongbin.top:3006

  • 评论列表
  • url: /api/cmtlist
  • type: get
  • 参数:无
  • 发表评论
  • url: /api/addcmt
  • type: post
  • 参数:username, content
  • 新闻列表
  • url: /api/news
  • type: get
  • 参数:无

实现步骤

  • 新闻列表

    1、获取新闻数据

    2、定义template模板

    3、编译模板

    4、定义时间过滤器

    5、定义补零函数

全局事件处理

http://www.jquery123.com/category/ajax/global-ajax-event-handlers/

自学内容(作业)

  • $(selector).load()
  • $.getJSON()
  • $.getScript() 简单概括以上方法的作用和基本用法。

http://www.liulongbin.top:3006/api/addbook

XMLHttpRequest Level2

旧版XMLHttpRequest的缺点

  • 只支持文本数据的传输,无法用来读取和上传文件
  • 传送和接收数据时,没有进度信息,只能提示有没有完成
  • 受到"同源限制",只能向同一域名的服务器发送请求

XMLHttpRequest2新功能

  • 可以设置HTTP请求的时限
  • 可以使用FormData对象管理表单数据
  • 可以上传文件
  • 可以获得数据传输的进度信息
  • 可以请求不同域名下的数据(跨域请求)
  • 可以获取服务器端的二进制数据

设置HTTP请求时限

有时,Ajax操作很耗时,而且无法预知要花多少时间。如果网速很慢,用户可能要等很久。新版本的XMLHttpRequest对象,增加了timeout属性,可以设置HTTP请求的时限:

js
xhr.timeout = 3000 // 单位:ms

上面的语句,将最长等待时间设为3000毫秒。过了这个时限,就自动停止HTTP请求。与之配套的还有一个timeout 事件,用来指定回调函数:

js
xhr.ontimeout =function (event) {
  alert('请求超时! ')
}

FormData对象

ajax操作往往用来传递表单数据,为了方便表单处理,HTML5新增了一个FormData对象,可以模拟表单

首先,新建一个FormData对象

js
var formData = new FormData()

然后,为它添加表单项

js
formData.append('username','张三')
formData.append('id','123456')

最后,直接传送这个FormData对象,这与提交网页表单的效果完全一样

js
xhr.send(formData)

FormData对象也可以用来获取网页表单的值。根据form表单创建FormData对象,会自动将表单数据填充到FormData对象中

js
    var form = document.getElementById('myForm')
    var formData = new FormData(form) // 根据form表单创建FormData对象,会自动将表单数据填充到FormData对象中
    formData.append('secret','123456') // 添加一个表单项
    xhr.open('POST', form.action)
    xhr.send(formData)

示例:

js
+   <form id="form1">
+       <input type="text" name="age">
+       <input type="text" name="gender">
+       <button type="submit">提交</button>
    </form>

    <script>
+       var form = document.querySelector('#form1'); // 获取form表单

+       form.addEventListener('submit', function (e) {
+           e.preventDefault(); // 阻止默认行为

+           var fd = new FormData(form); // 根据form表单创建FormData对象
+           fd.append('name', '张三');
+          fd.append('pass', '123456');

            var xhr = new XMLHttpRequest();
+           xhr.open('POST', 'http://www.liulongbin.top:3006/api/formdata');
+           xhr.send(fd);
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4 && xhr.status === 200) {
                    console.log(JSON.parse(xhr.responseText));
                }
            }
        });
    </script>

上传文件

新版XMLHttpRequest对象不仅可以发送文本信息,还可以上传文件

实现步骤:

  • 定义UI结构
  • 验证是否选择了文件
  • 向FormData中追加文件
  • 使用xhr发起上传文件的请求
  • 监听onreadystatechange事件

假定files是一个选择文件的表单元素(input[type="file"]),我们将它装入FormData对象

js
var formData = new FormData()
for (let i = 0; i < files.length; i++) {
    formData.append(`files[${i}]`, files[i])
}

然后发送这个FormData对象

js
xhr.send(formData)

示例:

html
    <form action="" method="post">
+        <input type="file" name="files" id="" />
        <button id="btnUpload">上传文件</button>
    </form>

    <script>
        document.querySelector('#btnUpload').addEventListener('click', function (e) {
+            e.preventDefault();

+            var fd = new FormData();
+            var files = document.querySelector('input[type=file]').files; // 获取文件上传input中的files

+            // 判断files的length属性
            if (files.length == 0) {
                return alert('没有选中任何文件!');
            }

            // 循环将files文件数组追加到FormData中去
            for (var i = 0; i < files.length; i++) {
+                fd.append(`files[${i}]`, files[i]);
            }

            // 执行上传文件
            var xhr = new XMLHttpRequest();
+            xhr.open('POST', 'http://www.liulongbin.top:3006/api/upload/avatar');
+            xhr.send(fd);
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4 && xhr.status == 200) {
+                    console.log(JSON.parse(xhr.responseText));
                }
            }
        });
    </script>

跨域资源共享(CORS)

新版的XMLHttpRequest对象,可以向不同域名的服务器发出Http请求,也叫做跨域资源共享

使用跨域资源共享的前提是,浏览器必须支持这个功能,而且服务端必须同意这种跨域请求。如果能满足以上条件,则代码的写法与不跨域的请求完全一样

js
xhr.open('GET','www.test.com')

接受二进制数据

老版本的XMLHttpRequest对象,只能从服务器取回文本数据(否则它的名字就不用XML起头了),新版则可以取回二进制数据

这里分为两种做做法。较老的做法是该写数据的MIMEType,将服务器返回的二进制数据伪装成文本数据,并且告诉浏览器这是用户自定义的字符集

js
xhr.overrideMimeType("text/plain;charset=x-user-defined")

然后,用responseText属性接受服务器返回的二进制数据

js
var binStr = xhr.responseTetxt

由于这时浏览器把它当做文本数据,所以还必须再一个个字节的还原成二进制数据

js
for (let i = 0,len = binStr.length; i < len; ++i) {
    let c = binStr.charCodeAt(i)
    let byte = c & 0xff
}

最后一行的位运算"c & 0xff",表示在每个字符的两个字节之中,只保留后一个字节,将前一个字节扔掉。原因是浏览器解读字符的时候,会把字符自动解读成Unicode的oxF7oo-oxF7ff区段

还有一种方法接受二进制数据

从服务器取回二进制数据,如果服务器返回文本数据,这个属性的值是‘TEXT',这是默认值,较新的浏览器还支持其他值,也就是说,可以接受其他格式的数据

你可以把responseType设为blob,表示服务器传回的是二进制对象

js
var xhr = new XMLHttpRequest()
xhr.open('GET','/path/to/img.png')
xhr.responseType = 'blob'

接受数据的时候,用浏览器自带的Blob对象即可

js
var blob = new Blob([xhr.response], {type: 'image/png'})

注意,是读取xhr.response,而不是xhr.responseTextjs

你还可以将responseType设为arrayBuffer,把二进制数据装在数组里

js
var xhr = new XMLHttpRequest()
xhr.open('GET','/path/to/img.png')
xhr.responseType = 'arraybuffer'

接受数据的时候,需要遍历这个数组

js
var arrayBuffer = xhr.response
if (arrayBuffer) {
    var byteArray = new Uint8Array(arrayBuffer)
    for (let i = 0;i < byteArray.byteLength; i++) {
        //do something
    }
}

进度信息

新版本的XMLHttpRequest对象,传送数据的时候,有一个progress事件,用来返回进度信息。

它分成上传和下载两种情况,下载的progress事件属于XMLHttpRequest对象上传的progress事件属于XMLHttpRequest.upload对象

我们先定义progress事件的回调函数

js
xhr.onprogress = updateProgress
xhr.upload.onprogress = updateProgress

然后在回调函数里面,使用这个事件的一些属性

js
function updateProgress(e) {
    if(e.lengthComputable) { // 布尔值,表示当前上传的资源是否具有可计算的长度
        var percentComplete = e.loaded / e.total
    }
}

上面的代码中,event.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable不为真,则event.total等于0。

与progress事件相关的,还有其他五个事件,可以分别指定回调函数:

  • load事件:传输成功完成。
  • abort事件:传输被用户取消。
  • error事件:传输中出现错误。
  • loadstart事件:传输开始。
  • loadEnd事件:传输结束,但是不知道成功还是失败。

示例:

html
js

基于BootStrap绘制进度条

axios

什么是axios

Axios是专注于网络数据请求的库。

相比于原生的XMLHttpRequest对象,axios简单易用。

相比于jQuery,axios 更加轻量化,只专注于网络数据请求。

axios发起GET请求

语法

js
axios.get('url', { params: { /*参数*/ } }).then(callback);

具体的请求示例:

js
js
js
js
js
js
js
js
js
js

跨域

相关概念

同源策略是浏览器的一种安全策略,所谓同源是指域名,协议,端口完全相同,只有同源的地址才可以相互通过AJAX 的方式请求。 同源或者不同源说的是两个地址之间的关系,不同源地址之间请求我们称之为跨域请求 什么是同源?例如:http://www.example.com/detail.html 与以下地址对比

对比地址是否同源原因
http://api.example.com/detail.html不同源域名不同
https//www.example.com/detail.html不同源协议不同
http://www.example.com*:8080*/detail.html不同源端口不同
http://api.example.com*:8080*/detail.html不同源域名、端口不同
https😕/api.example.com/detail.html不同源协议、域名不同
https😕/www.example.com*:8080*/detail.html不同源端口、协议不同

解决方案

现代化的 Web 应用中肯定会有不同源的现象,所以必然要解决这个问题,从而实现跨域请求。

参考:http://rickgray.me/solutions-to-cross-domain-in-browser

JSONP

JSON with Padding,是一种借助于 script 标签发送跨域请求的技巧。其原理就是在客户端借助 script 标签请求服务端的一个动态网页(php 文件),服务端的这个动态网页返回一段带有函数调用的 JavaScript 全局函数调用的脚本,将原本需要返回给客户端的数据传递进去。 以后绝大多数情况都是采用 JSONP 的手段完成不同源地址之间的跨域请求 客户端 http://www.zce.me/users-list.html

js
// script标签里面不能有async,加了就表示是异步加载
<script src="http://api.zce.me/users.php?callback=foo"></script>

服务端 http://api.zce.me/users.php?callback=foo 返回的结果

js
foo(['我', '是', '你', '原', '本', '需', '要', '的', '数', '据'])

总结一下:由于 XMLHttpRequest 无法发送不同源地址之间的跨域请求,所以我们必须要另寻他法,script 这种方案就是我们最终选择的方式,我们把这种方式称之为 JSONP,如果你不了解原理,先记住怎么用,多用一段时间再来看原理。

问题:

  1. JSONP 需要服务端配合,服务端按照客户端的要求返回一段 JavaScript 调用客户端的函数
  2. 只能发送 GET 请求

注意:JSONP 用的是 script 标签,和 A JAX 提供的 XMLHttpRequest 没有任何关系!!! jQuery 中使用 JSONP 就是将 dataType 设置为 jsonp

其他常见的AJAX封装库:

  • Axios

CORS

Cross Origin Resource Share,跨域资源共享

js
// 允许远端访问
header('Access‐Control‐Allow‐Origin: *');

这种方案无需客户端作出任何变化(客户端不用改代码),只是在被请求的服务端响应的时候添加一个 Access-Control-Allow-Origin 的响应头,表示这个资源是否允许指定域请求。

XMLHttpRequest 2.0

暂作了解,无需着重看待 更易用,更强大

onload / onprogress

js
var xhr = new XMLHttpRequest()
xhr.open('GET', './time.php')
xhr.onload = function () {
   // onload readyState === 4
   console.log(this.readyState);
}
xhr.onprogress = function () {
   // onload readyState === 3
   console.log(this.readyState);
}
xhr.send(null);

FormData

以前 A JAX 只能提交字符串,现在可以提交 二进制 的数据

案例

异步上传文件

参考链接